from google.appengine.ext import db
from google.appengine.api import users

import datetime

MAX_FETCH = 500
NO_CLOCKOUT_DATETIME = datetime.datetime(1900,1,1)


# Entity Tables
class Project(db.Model):
    """Models a Project"""
    name = db.StringProperty()
    user = db.UserProperty()

class Punch(db.Model):
    """Models an individual Punch"""
    user = db.UserProperty()    
    in_out_datetimes = db.ListProperty(datetime.datetime)
    project = db.ReferenceProperty(reference_class=Project, collection_name="punches")

# model methods
def is_clocked_in():
    result = Punch.all().filter("in_out_datetimes =", NO_CLOCKOUT_DATETIME).filter("user =", users.get_current_user()).fetch(1)
    if len(result) == 1:
        return (result[0].key(), result[0].project.name)
    else:
        return ""

def get_projects(all=False):
    clocked_in = is_clocked_in()
    if clocked_in and not all:
        key = clocked_in[0]
        return [get_punch(key).project]
    else:
        return Project.all().filter("user =", users.get_current_user()).order("name").fetch(MAX_FETCH)

def get_project_names(all=False):
    return [p.name for p in get_projects(all)]

def get_punch(key):
    punch = Punch.get(key)
    return punch

def get_project(key):
    project = Project.get(key)
    return project

def get_project_sums(start_datetime, end_datetime, all=False):
    """
    Returns an iterable object with project and sum
    as values in each item in the object
    """
    sums = []
    grand_sum = 0.0
    for project_name in get_project_names(all=True):
        sum = get_sum_for_project_by_datetime(project_name, start_datetime,
                            end_datetime)
        if float(sum) != 0.0 or all:
            sums.append({"project":project_name,
                         "sum":sum})
            grand_sum += float(sum)
    return (sums, grand_sum)

def _convert_timedelta_to_hours(td_obj):
    days = td_obj.days
    seconds = td_obj.seconds
    hours = days * 24
    hours += (seconds / 60.0 / 60.0)
    return hours
   
def get_sum_for_project_by_datetime(project_name, local_daystart_datetime, 
                                    dayafter_daystart_datetime):
    project_sum = 0.0
    punches = get_punches_for_day(local_daystart_datetime, dayafter_daystart_datetime)
    for punch in punches:
        if punch.project.name == project_name:
            if punch.in_out_datetimes[1] == NO_CLOCKOUT_DATETIME:
                out_datetime = datetime.datetime.now()
            else:
                out_datetime = punch.in_out_datetimes[1]
            punch_delta = out_datetime - punch.in_out_datetimes[0]
            hours = _convert_timedelta_to_hours(punch_delta)
            project_sum += hours
    project_sum = "%05.2f" % project_sum
    return project_sum

def get_todays_punches(local_daystart_datetime, dayafter_daystart_datetime):
    punches = get_punches_for_day(local_daystart_datetime, dayafter_daystart_datetime)
    return punches

def get_punches_for_day(day_start, next_day_start):
    punches = Punch.all()
    punches.filter("in_out_datetimes >=", day_start)
    punches.filter("in_out_datetimes <", next_day_start)
    punches.filter("user =", users.get_current_user())
    punches.order("-in_out_datetimes")
    return punches.fetch(MAX_FETCH)
  
def punches_in_project(project_key):
    project = get_project(project_key)
    count = Punch.all().filter("project =", project).filter("user =", users.get_current_user()).count(1)
    return count > 0
    
def _get_project(project_name):
    "Get an already existing project from it's name"
    projects = Project.all().filter("name =", project_name).filter("user =", users.get_current_user()).fetch(1)
    return projects[0]

def save_punch(project_key, in_utc_datetime=None, out_utc_datetime=NO_CLOCKOUT_DATETIME, 
               punch_key=None):
    "creates or edits a punch entity"
    if not punch_key:
        punch = Punch()
    else:
        punch = get_punch(punch_key)  
    # clear out the datetimes so we can redo them here
    punch.in_out_datetimes = [] 
    # we are assuming that the project already exists
    punch.project = get_project(project_key)
    punch.in_out_datetimes.append(in_utc_datetime)
    punch.in_out_datetimes.append(out_utc_datetime)
    punch.user = users.get_current_user()
    punch.put()
    
def delete_punch(key):
    punch = get_punch(key)
    punch.delete()
        
def save_project(project_name, punch_key=None):
    if not punch_key:
        project = Project(name=project_name)
    else:
        project = get_project(punch_key)
        project.name = project_name
    project.user = users.get_current_user() 
    project.put()
    
def delete_project(key):
    project = get_project(key)
    project.delete()